home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dc1 / asm2.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  42KB  |  1,921 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  ASM2.C
  9.  *
  10.  */
  11.  
  12. /*
  13. **      $Filename: asm2.c $
  14. **      $Author: dice $
  15. **      $Revision: 30.326 $
  16. **      $Date: 1995/12/24 06:09:35 $
  17. **      $Log: asm2.c,v $
  18.  * Revision 30.326  1995/12/24  06:09:35  dice
  19.  * .
  20.  *
  21.  * Revision 30.5  1994/06/13  18:37:22  dice
  22.  * .
  23.  *
  24.  * Revision 30.0  1994/06/10  18:04:46  dice
  25.  * .
  26.  *
  27.  * Revision 1.6  1993/11/22  00:28:36  jtoebes
  28.  * Final cleanup to eliminate all cerror() messages with strings.
  29.  *
  30.  * Revision 1.5  1993/09/11  22:35:28  jtoebes
  31.  * Fixed BUG06009.
  32.  * asm_cmp optimized a compare into a tst instruction for unsigned values.
  33.  * Eliminated this improper optimization.
  34.  *
  35.  * Revision 1.4  1993/09/06  09:31:42  jtoebes
  36.  * Fixed BUG06066 - Enforcer hit with float code.
  37.  * CallAsmSupport did not check for the register being null.
  38.  *
  39. **/
  40.  
  41. #include "defs.h"
  42. #include "asm.h"
  43.  
  44. #define Max(a,b)    (((a) > (b)) ? (a) : (b))
  45.  
  46. Prototype void asm_move(Exp *, Stor *, Stor *);
  47. Prototype void asm_move_cast(Exp *, Stor *, Stor *);
  48. Prototype long ReverseOrder(short);
  49. Prototype void asm_cmp(Exp *, Stor *, Stor *, short *);
  50. Prototype long asm_div(Exp *, Stor *, Stor *, Stor *, short);
  51. Prototype long asm_mul(Exp *, Stor *, Stor *, Stor *);
  52. Prototype long asm_mul_requires_call(long);
  53. Prototype void asm_shift(Exp *, long, Stor *, Stor *, Stor *);
  54. Prototype void CallAsmSupport(Exp *, char *, Stor *, Stor *, Stor *, short);
  55. Prototype void asm_bfext(Exp *, Stor *, Stor *);
  56. Prototype void asm_bfsto(Exp *, Stor *, Stor *);
  57. Prototype void asm_bftst(Exp *, Stor *);
  58. Prototype void asm_blockfill(Exp *, Stor *, long, char);
  59. Prototype void asm_illegal(void);
  60. Prototype void asm_moveqAndSwap(long, char, short);
  61.  
  62. Local void asm_blockop(Exp *, char *, short, Stor *, Stor *);
  63. Local void OptimizeBitField(Stor *, Stor *);
  64.  
  65. /*
  66.  *  asm_blockop()   is used for block moves and block compares.  When
  67.  *            used for block compares the loop breaks out when
  68.  *            a not-equal condition occurs.  The 'cond' passed
  69.  *            to the routine only effects the final branch, NOT
  70.  *            the loop-breakout condition.
  71.  */
  72.  
  73. Local void
  74. asm_blockop(Exp *exp, char *op, short cond, Stor *s, Stor *d)
  75. {
  76.     long n = s->st_Size >> 2;
  77.     long i;
  78.     long o1 = s->st_Offset;
  79.     long o2 = d->st_Offset;
  80.     long label;
  81.     long breaklabel;
  82.     Stor scnt, mcnt, asrc, adst;
  83.     char *dbstr;
  84.     short doRemainder = 1;
  85.  
  86.     /*
  87.     printf("block %s %s (%d %d) (%d %d)\n",
  88.     StorToString(s, NULL), StorToString(d, NULL), s->st_Size, d->st_Size,
  89.     s->st_Type, d->st_Type
  90.     );
  91.     */
  92.  
  93.     breaklabel = AllocLabel();
  94.  
  95.     switch(cond) {
  96.     case COND_EQ:
  97.     case COND_NEQ:
  98.     dbstr = "dbne";     /*  loop until not equal or done (eq)   */
  99.     break;
  100.     default:
  101.     dbstr = "dbf";
  102.     break;
  103.     }
  104.  
  105.  
  106.     if (s->st_Type < ST_RelReg || s->st_Type > ST_RegIndex)
  107.     yerror(exp->ex_LexIdx, EERROR_BLOCK_OPERATION_SOURCE);
  108.     if (d->st_Type < ST_RelReg || d->st_Type > ST_RegIndex)
  109.     yerror(exp->ex_LexIdx, EERROR_BLOCK_OPERATION_DEST);
  110.  
  111.     /*
  112.      *    In the default case we load a data register with the lw count
  113.      *    and two address registers with the base addresses.
  114.      */
  115.  
  116.     switch(n) {
  117.     default:
  118.     --n;
  119.     LockStorage(s);
  120.     LockStorage(d);
  121.     if (n > 65534) {
  122.         AllocDataRegister(&mcnt, 2);
  123.         AllocDataRegister(&scnt, 4);
  124.     } else {
  125.         AllocDataRegister(&scnt, 2);
  126.     }
  127.  
  128.     /*
  129.      *  If long aligned we can reuse s and d registers, but if not
  130.      *  we need them!
  131.      */
  132.  
  133.     if (s->st_Size & 3) {
  134.         AllocAddrRegister(&asrc);
  135.         AllocAddrRegister(&adst);
  136.     } else {
  137.         UnlockStorage(s);
  138.         AllocAddrRegister(&asrc);
  139.         UnlockStorage(d);
  140.         LockStorage(s);
  141.         AllocAddrRegister(&adst);
  142.         LockStorage(d);
  143.     }
  144.     LockStorage(&asrc);
  145.     LockStorage(&adst);
  146.     asm_movei(exp, n, &scnt);
  147.     if (n > 65534) {
  148.         printf("\tmove.l\tD%d,D%d\n", scnt.st_RegNo, mcnt.st_RegNo);
  149.         printf("\tswap\tD%d\n", mcnt.st_RegNo);
  150.     }
  151.     asm_lea(exp, s, 0, &asrc);
  152.     asm_lea(exp, d, 0, &adst);
  153.     UnlockStorage(s);
  154.     UnlockStorage(d);
  155.     asrc.st_Type = ST_RelReg;
  156.     asrc.st_Offset = 0;
  157.     adst.st_Type = ST_RelReg;
  158.     adst.st_Offset = 0;
  159.  
  160.     label = AllocLabel();
  161.     asm_label(label);
  162.     printf("\t%s.l\t(A%d)+,(A%d)+\n", op, asrc.st_RegNo - RB_ADDR, adst.st_RegNo - RB_ADDR);
  163.     printf("\t%s\tD%d,l%ld\n", dbstr, scnt.st_RegNo, label);
  164.     if (n > 65534) {
  165.         if (cond)
  166.         asm_condbra(COND_NEQ, breaklabel);
  167.         printf("\t%s\tD%d,l%ld\n", dbstr, mcnt.st_RegNo, label);
  168.     }
  169.  
  170.     /*
  171.      *  Handle tail-end case here.    Can't handle tail end case
  172.      *  down below more because the structure might be larger then
  173.      *  128 bytes.
  174.      */
  175.  
  176.     if (s->st_Size & 3) {
  177.         if (cond)
  178.         asm_condbra(COND_NEQ, breaklabel);
  179.         switch(s->st_Size & 3) {
  180.         case 3:
  181.         case 2:
  182.         printf("\t%s.w\t(A%d)+,(A%d)+\n", op, asrc.st_RegNo - RB_ADDR, adst.st_RegNo - RB_ADDR);
  183.         if ((s->st_Size & 1) == 0)
  184.             break;
  185.         if (cond)
  186.             asm_condbra(COND_NEQ, breaklabel);
  187.         /* fall through */
  188.         case 1:
  189.         printf("\t%s.b\t(A%d),(A%d)\n", op, asrc.st_RegNo - RB_ADDR, adst.st_RegNo - RB_ADDR);
  190.         break;
  191.         }
  192.         doRemainder = 0;
  193.     }
  194.  
  195.     UnlockStorage(&asrc);
  196.     UnlockStorage(&adst);
  197.     FreeRegister(&adst);
  198.     FreeRegister(&asrc);
  199.     FreeRegister(&scnt);
  200.     if (n > 65534)
  201.         FreeRegister(&mcnt);
  202.     break;
  203.     case 4:    /*  note, LGBO_SIZE (machine.h) */
  204.     case 3:
  205.     case 2:
  206.     case 1:
  207.     if (cond)
  208.         AllocDataRegister(&mcnt, 4);
  209.  
  210.     for (i = n - 1; i >= 0; --i) {
  211.         s->st_Offset = o1 + i * 4;
  212.         d->st_Offset = o2 + i * 4;
  213.         if (cond) {
  214.         outop("move", 4, d, &mcnt);
  215.         outop(op, 4, s, &mcnt);
  216.         } else {
  217.         outop(op, 4, s, d);
  218.         }
  219.  
  220.         if (cond && (i || (s->st_Size & 3)))
  221.         asm_condbra(COND_NEQ, breaklabel);
  222.     }
  223.     if (cond)
  224.         FreeRegister(&mcnt);
  225.     break;
  226.     case 0:
  227.     break;
  228.     }
  229.  
  230.     /*
  231.      *    do remainder.  s and d are guarenteed to contain source and
  232.      *    destination bases only if (s->st_Size & 3) != 0
  233.      */
  234.  
  235.     if (doRemainder) {
  236.     s->st_Offset = o1 + (s->st_Size & ~3);
  237.     d->st_Offset = o2 + (d->st_Size & ~3);
  238.  
  239.     switch(s->st_Size & 3) {
  240.     case 0:
  241.         break;
  242.     case 3:     /*     2 + 1    */
  243.     case 2:
  244.         if (cond) {
  245.         AllocDataRegister(&mcnt, 4);
  246.         outop("move", 2, d, &mcnt);
  247.         outop(op, 2, s, &mcnt);
  248.         FreeRegister(&mcnt);
  249.         } else {
  250.         outop(op, 2, s, d);
  251.         }
  252.         if ((s->st_Size & 1) == 0)
  253.         break;
  254.         s->st_Offset += 2;
  255.         d->st_Offset += 2;
  256.     case 1:
  257.         if (cond) {
  258.         AllocDataRegister(&mcnt, 4);
  259.         outop("move", 1, d, &mcnt);
  260.         outop(op, 1, s, &mcnt);
  261.         FreeRegister(&mcnt);
  262.         } else {
  263.         outop(op, 1, s, d);
  264.         }
  265.         break;
  266.     default:
  267.         Assert(0);
  268.     }
  269.     }
  270.     if (cond)
  271.     asm_label(breaklabel);
  272.  
  273.     s->st_Offset = o1;
  274.     d->st_Offset = o2;
  275. }
  276.  
  277. #ifdef NOTDEF
  278. /*
  279.  *  fill a block (d is a pointer) with a value, simple stupid
  280.  *
  281.  *  currently d must be register-relative
  282.  */
  283.  
  284. void
  285. asm_blockfill(exp, d, n, v)
  286. Exp *exp;
  287. Stor *d;
  288. long n;
  289. char v;
  290. {
  291.     Stor t;
  292.     Stor r;
  293.     Stor adst;
  294.     Stor dcnt;
  295.     long label;
  296.  
  297.     asm_getind(&VoidPtrType, d, &t, -1, -1, 0);
  298.  
  299.     switch(n) {
  300.     case 0:
  301.     break;
  302.     case 6:
  303.     t.st_Size = 2;
  304.     asm_movei(exp, 0, &t);
  305.     n -= 2;
  306.     t.st_Offset += 2;
  307.     case 1:
  308.     case 2:
  309.     case 4:
  310.     t.st_Size = n;
  311.     asm_movei(exp, 0, &t);
  312.     break;
  313.     case 8:
  314.     case 12:
  315.     case 16:
  316.     AllocDataRegister(&r, 4);
  317.     t.st_Size = 4;
  318.     asm_movei(exp, 0, &r);
  319.     while (n) {
  320.         asm_move(exp, &r, &t);
  321.         t.st_Offset += 4;
  322.         n -= 4;
  323.     }
  324.     FreeRegister(&r);
  325.     break;
  326.     default:        /*    byte fill   */
  327.     label = AllocLabel();
  328.  
  329.     AllocDataRegister(&r, 4);
  330.     AllocDataRegister(&dcnt, 2);
  331.     AllocAddrRegister(&adst);
  332.     asm_movei(exp, 0, &r);
  333.     asm_move(exp, d, &adst);
  334.     asm_movei(exp, n-1, &dcnt);
  335.     asm_label(label);
  336.     printf("\tmove.b\tD%d,(A%d)+\n", r.st_RegNo, adst.st_RegNo - RB_ADDR);
  337.     printf("\tdbf\tD%d,l%ld\n", dcnt.st_RegNo, label);
  338.     FreeRegister(&r);
  339.     FreeRegister(&dcnt);
  340.     FreeRegister(&adst);
  341.     break;
  342.     }
  343. }
  344.  
  345. #endif
  346.  
  347. /*
  348.  *  asm_move()    strictly moves objects of the same size
  349.  */
  350.  
  351. void
  352. asm_move(exp, s, d)
  353. Exp *exp;
  354. Stor *s;
  355. Stor *d;
  356. {
  357.     /*
  358.     fprintf(stderr, "move %s %s (%d %d) (%d %d)\n",
  359.     StorToString(s, NULL), StorToString(d, NULL), s->st_Size, d->st_Size,
  360.     s->st_Type, d->st_Type
  361.     );
  362.     */
  363.  
  364.     if (d->st_Flags & SF_LEA)
  365.     yerror(exp->ex_LexIdx, EFATAL_DEST_NOT_LVALUE);
  366.  
  367.     if (SameStorage(s, d))
  368.     return;
  369.     if (s->st_Type == ST_IntConst) {
  370.     int value = s->st_IntConst;
  371.     int swapit = 0;
  372.  
  373.     switch (d->st_Size) {
  374.     case 1:     /*    e.g. unsigned 0xF0 -> char == moveq #-10    */
  375.         value = (char)value;
  376.         break;
  377.     case 2:     /*    e.g. unsigned 0xFFF0 -> short == moveq #-10 */
  378.         value = (short)value;
  379.         break;
  380.     }
  381.  
  382.     /*
  383.      *  can we moveq or moveq/swap ?
  384.      *
  385.      *  note: bug in lattice C, comparison with 0x is done signed. 0x
  386.      *  hex constant is supposed to be unsigned.
  387.      */
  388.  
  389.     if ((ulong)value >= 0x10000 && (long)value < -128 && (long)value > 127) {
  390.         swapit = 1;
  391.         value = ((ulong)value >> 16) | ((ulong)value << 16);
  392.     }
  393.     if (value >= -128 && value < 128) {
  394.         Stor stor;
  395.  
  396.         if (d->st_Type == ST_Reg) {
  397.         if (d->st_RegNo < RB_ADDR) {
  398.             asm_moveqAndSwap(value, d->st_RegNo + '0', swapit);
  399. #ifdef NOTDEF
  400.             printf("\tmoveq.l\t#%d,D%c\n", value, d->st_RegNo + '0');
  401.             if (swapit)
  402.             printf("\tswap\tD%c\n", d->st_RegNo + '0');
  403. #endif
  404.             return;
  405.         }
  406.  
  407.         /*
  408.          *  optimize for address, move #n,An sign extends to
  409.          *  address register.
  410.          */
  411.  
  412.         if (s->st_IntConst == 0) {  /*    value may be invalid due to swap */
  413.             outop("suba", 4, d, d);
  414.             return;
  415.         }
  416.         if (s->st_IntConst < 32768) {
  417.             outop("move", 2, s, d);
  418.             return;
  419.         }
  420.         }
  421.         if (d->st_Size == 4) {
  422.         AllocDataRegister(&stor, 4);
  423.         asm_moveqAndSwap(value, stor.st_RegNo + '0', swapit);
  424. #ifdef NOTDEF
  425.         printf("\tmoveq.l\t#%d,D%c\n", value, stor.st_RegNo + '0');
  426.         if (swapit)
  427.             printf("\tswap\tD%c\n", stor.st_RegNo + '0');
  428. #endif
  429.         outop("move", 0, &stor, d);
  430.         FreeRegister(&stor);
  431.         return;
  432.         }
  433.     }
  434.  
  435.     /*
  436.      *  note: value may be invalid due to swap
  437.      */
  438.  
  439.     outop("move", 0, s, d);
  440.     return;
  441.     }
  442.     if (s->st_Type == ST_FltConst) {
  443.     long fltv[4];
  444.     long offset = d->st_Offset;
  445.     long size   = d->st_Size;
  446.     short i;
  447.  
  448.         /* Make sure that we are not trying to do a move on something that we   */
  449.         /* can't bump the offset for an indirect move.  In the case of a simple */
  450.         /* 4 byte float, it is legal to have a direct register.  Also, when we  */
  451.         /* Move to 68881 support, we will need to relax this check              */
  452.     if ((d->st_Type < ST_RelReg || d->st_Type > ST_RegIndex) &&
  453.         ((d->st_Type != ST_Reg) && (size != 4)))
  454.     {
  455.         dbprintf(("softerror, blockop struct, type d=%d\n", d->st_Type));
  456.         Assert(0);
  457.     }
  458.  
  459.     asm_fltconst(exp, s, fltv);
  460.  
  461.     d->st_Size = 4;
  462.     for (i = 0; i < size; i += 4) {
  463.         asm_movei(exp, fltv[i>>2], d);
  464.         d->st_Offset += 4;
  465.     }
  466.     d->st_Offset = offset;
  467.     d->st_Size   = size;
  468.     return;
  469.     }
  470.     if (s->st_Size != d->st_Size)
  471.     {
  472.     dbprintf(("asm_move: size mismatch %ld %ld", s->st_Size, d->st_Size));
  473.     Assert(0);
  474.     }
  475.  
  476.     if (s->st_Flags & SF_LEA) {
  477.     if (d->st_Size != 4)
  478.     {
  479.         dbprintf(("move ptr, dest size not 4"));
  480.         Assert(0);
  481.     }
  482.     if (d->st_Type == ST_Reg && d->st_RegNo >= RB_ADDR) {
  483.         outop("lea", 4, s, d);
  484.     } else if (s->st_Type == ST_RelReg && s->st_Offset == 0) {
  485.         s->st_Type = ST_Reg;
  486.         outop("move", 4, s, d);
  487.         s->st_Type = ST_RelReg;
  488.     } else {
  489.         Stor t;
  490.         LockStorage(s);
  491.         AllocAddrRegister(&t);
  492.         UnlockStorage(s);
  493.         outop("lea", 4, s, &t);
  494.         outop("move", 0, &t, d);
  495.         FreeRegister(&t);
  496.     }
  497.     return;
  498.     }
  499.     if (s->st_Size < d->st_Size)    /* XXX != */
  500.     eprintf(1, "move: size mismatch %d %d\n", s->st_Size, d->st_Size);
  501.  
  502.     if (s->st_Size <= 4 && s->st_Size != 3) {
  503.     Stor stor;
  504.     /* We have to check for the case where we are doing a byte move from an */
  505.     /* address register and handle it specially.                            */
  506.     /* To accomplish this, we will need a data register.                    */
  507.     if ((s->st_Size == 1) &&       /* Byte move                             */
  508.         (s->st_Type == ST_Reg) &&  /* From a register                       */
  509.         (s->st_RegNo >= RB_ADDR))  /* But it must be an address register    */
  510.     {
  511.  
  512.        AllocDataRegister(&stor, 4);
  513.        s->st_Size = 2;
  514.        outop("move", 0, s, &stor);
  515.        s->st_Size = 1;
  516.        s = &stor;
  517.     }
  518.     outop("move", 0, s, d);
  519.     return;
  520.     }
  521.     asm_blockop(exp, "move", 0, s, d);
  522. }
  523.  
  524. /*
  525.  *  This is a hack.. this combination occurs so often that using printf()s
  526.  *  effects the speed of compilation!
  527.  */
  528.  
  529. void
  530. asm_moveqAndSwap(long value, char dregC, short swapit)
  531. {
  532.     char *ptr = StorBuf[0];
  533.  
  534.     ptr[0] = '\t';
  535.     ptr[1] = 'm';
  536.     ptr[2] = 'o';
  537.     ptr[3] = 'v';
  538.     ptr[4] = 'e';
  539.     ptr[5] = 'q';
  540.     ptr[6] = '.';
  541.     ptr[7] = 'l';
  542.     ptr[8] = '\t';
  543.     ptr[9] = '#';
  544.     ptr += 10;
  545.     if (value) {
  546.     ptr = itodec(ptr, value);
  547.     } else {
  548.     *ptr = '0';
  549.     ++ptr;
  550.     }
  551.  
  552.     ptr[0] = ',';
  553.     ptr[1] = 'D';
  554.     ptr[2] = dregC;
  555.     ptr[3] = '\n';
  556.     ptr += 4;
  557.  
  558.     if (swapit) {
  559.     ptr[0] = '\t';
  560.     ptr[1] = 's';
  561.     ptr[2] = 'w';
  562.     ptr[3] = 'a';
  563.     ptr[4] = 'p';
  564.     ptr[5] = '\t';
  565.     ptr[6] = 'D';
  566.     ptr[7] = dregC;
  567.     ptr[8] = '\n';
  568.     ptr += 9;
  569.     }
  570.     fwrite(StorBuf[0], ptr - StorBuf[0], 1, stdout);
  571. #ifdef NOTDEF
  572.         printf("\tmoveq.l\t#%d,D%c\n", value, stor.st_RegNo + '0');
  573.         if (swapit)
  574.             printf("\tswap\tD%c\n", stor.st_RegNo + '0');
  575. #endif
  576. }
  577.  
  578.  
  579. /*
  580.  *  asm_move_cast() works like asm_move() but only on integer objects.    Objects
  581.  *  of different sizes may be moved.
  582.  */
  583.  
  584. void
  585. asm_move_cast(exp, s, d)
  586. Exp *exp;
  587. Stor *s;
  588. Stor *d;
  589. {
  590.     if (s->st_Size > d->st_Size) {
  591.     long off = s->st_Offset;
  592.     long size = s->st_Size;
  593.  
  594.     switch(s->st_Type) {
  595.     case ST_PtrConst:
  596.     case ST_RelReg:
  597.     case ST_RelArg:
  598.     case ST_RelName:
  599.     case ST_RelLabel:
  600.     case ST_RegIndex:
  601.         s->st_Offset += s->st_Size - d->st_Size;
  602.         break;
  603.     }
  604.     s->st_Size = d->st_Size;
  605.     asm_move(exp, s, d);
  606.     s->st_Offset = off;
  607.     s->st_Size = size;
  608.     return;
  609.     }
  610.     if (s->st_Size == d->st_Size) {
  611.     asm_move(exp, s, d);
  612.     return;
  613.     }
  614.     if (SameStorage(s, d)) {
  615.     if (s->st_Flags & SF_UNSIGNED) {
  616.         long val;
  617.         Stor con;
  618.  
  619.         if (s->st_Size == 1) {
  620.         if (d->st_Size == 2)
  621.             val = 0x00FF;
  622.         else
  623.             val = 0x000000FF;
  624.         } else {
  625.         val = 0x0000FFFF;
  626.         }
  627.         AllocConstStor(&con, val, &LongType);
  628.         asm_and(exp, &con, d, d);
  629.         return;
  630.     } else if (s->st_Type == ST_Reg && s->st_RegNo < RB_ADDR) {
  631.         if (s->st_Size == 1) {
  632.         if (d->st_Size >= 2)
  633.             outop("ext", 2, NULL, d);
  634.         if (d->st_Size == 4)
  635.             outop("ext", 4, NULL, d);
  636.         } else {
  637.         outop("ext", 4, NULL, d);
  638.         }
  639.         return;
  640.     }
  641.     }
  642.  
  643.     /*
  644.      *    not a reg or not same storage or not a reg and same storage.
  645.      */
  646.     {
  647.     Stor tmp;
  648.  
  649.     LockStorage(s);
  650.     AllocDataRegister(&tmp, d->st_Size);
  651.     UnlockStorage(s);
  652.     if (s->st_Flags & SF_UNSIGNED) {
  653.         asm_movei(exp, 0, &tmp);
  654.         tmp.st_Size = s->st_Size;
  655.         asm_move(exp, s, &tmp);
  656.         tmp.st_Size = d->st_Size;
  657.         asm_move(exp, &tmp, d);
  658.     } else {
  659.         tmp.st_Size = s->st_Size;
  660.         asm_move(exp, s, &tmp);
  661.         if (s->st_Size == 1)
  662.         outop("ext", 2, NULL, &tmp);
  663.         if (d->st_Size == 4)
  664.         outop("ext", 4, NULL, &tmp);
  665.         tmp.st_Size = d->st_Size;
  666.         asm_move(exp, &tmp, d);
  667.     }
  668.     FreeRegister(&tmp);
  669.     }
  670. }
  671.  
  672. /*
  673.  *  Reversing the opcode ordering in the compare is not the same as
  674.  *  cond = -cond
  675.  */
  676.  
  677. long
  678. ReverseOrder(short cond)
  679. {
  680.     switch(cond) {
  681.     case COND_LT:
  682.     return(COND_GT);
  683.     case COND_LTEQ:
  684.     return(COND_GTEQ);
  685.     case COND_GT:
  686.     return(COND_LT);
  687.     case COND_GTEQ:
  688.     return(COND_LTEQ);
  689.     case COND_EQ:
  690.     return(COND_EQ);
  691.     case COND_NEQ:
  692.     return(COND_NEQ);
  693.     case CF_UNS|COND_LT:
  694.     return(CF_UNS|COND_GT);
  695.     case CF_UNS|COND_LTEQ:
  696.     return(CF_UNS|COND_GTEQ);
  697.     case CF_UNS|COND_GT:
  698.     return(CF_UNS|COND_LT);
  699.     case CF_UNS|COND_GTEQ:
  700.     return(CF_UNS|COND_LTEQ);
  701.     case CF_UNS|COND_EQ:
  702.     return(CF_UNS|COND_EQ);
  703.     case CF_UNS|COND_NEQ:
  704.     return(CF_UNS|COND_NEQ);
  705.  
  706.     case -COND_LT:        /*    gteq    */
  707.     return(COND_LTEQ);
  708.     case -COND_LTEQ:        /*    gt    */
  709.     return(COND_LT);
  710.     case -COND_GT:        /*    lteq    */
  711.     return(COND_GTEQ);
  712.     case -COND_GTEQ:        /*    lt    */
  713.     return(COND_GT);
  714.     case -COND_EQ:        /*    neq    */
  715.     return(COND_NEQ);
  716.     case -COND_NEQ:        /*    eq    */
  717.     return(COND_EQ);
  718.  
  719.     case -(CF_UNS|COND_LT):    /*  gteq    */
  720.     return(CF_UNS|COND_LTEQ);
  721.     case -(CF_UNS|COND_LTEQ):    /*  gt        */
  722.     return(CF_UNS|COND_LT);
  723.     case -(CF_UNS|COND_GT):    /*  lteq    */
  724.     return(CF_UNS|COND_GTEQ);
  725.     case -(CF_UNS|COND_GTEQ):    /*  lt        */
  726.     return(CF_UNS|COND_GT);
  727.     case -(CF_UNS|COND_EQ):    /*  neq     */
  728.     return(COND_NEQ);
  729.     case -(CF_UNS|COND_NEQ):    /*  eq        */
  730.     return(COND_EQ);
  731.     }
  732.     dbprintf(("Unknown cond %d\n", cond));
  733.     Assert(0);
  734.     return(0);            /* not reached */
  735. }
  736.  
  737. void
  738. asm_cmp(exp, s1, s2, pcond)
  739. Exp *exp;
  740. Stor *s1;
  741. Stor *s2;
  742. short *pcond;
  743. {
  744.     Stor stor1;
  745.     Stor stor2;
  746.  
  747.     if ((s1->st_Flags | s2->st_Flags) & SF_BITFIELD)
  748.     {
  749.     dbprintf(("compare - bitfield"));
  750.     Assert(0);
  751.     }
  752.  
  753.     Assert(s1->st_Size == s2->st_Size);
  754.     if (s2->st_Type == ST_Reg) {
  755.     SWAPS(s1, s2);
  756.     *pcond = ReverseOrder(*pcond);
  757.     }
  758.     if (ImmStorage(s1)) {
  759.     SWAPS(s1, s2);
  760.     *pcond = ReverseOrder(*pcond);
  761.     }
  762.     if (!(s1->st_Flags & SF_LEA) && s2->st_Type == ST_IntConst) {
  763.     /*
  764.      *  if cmp.l #long and long is in moveq range then use
  765.      *  moveq/cmp instead.    But, if the constant is 0 then use
  766.      *  a tst instead.  Since we know the branch condition we could
  767.      *  also conceivably optimize compares with the constants 1 and
  768.      *  -1 as well (a >= 1 === a > 0).
  769.      */
  770.     if (s2->st_IntConst == 0 &&
  771.         (s1->st_Type != ST_Reg || s1->st_RegNo < RB_ADDR) &&
  772.         ((*pcond & CF_UNS) == 0)) {
  773.         outop("tst", 0, NULL, s1);
  774.         return;
  775.     }
  776.     if (s1->st_Size == 4 && s2->st_IntConst >= -128 && s2->st_IntConst < 128) {
  777.         LockStorage(s1);
  778.         AllocDataRegister(&stor1, 4);
  779.         UnlockStorage(s1);
  780.         asm_move(exp, s2, &stor1);
  781.         outop("cmp", 0, s1, &stor1);
  782.         *pcond = ReverseOrder(*pcond);
  783.         FreeRegister(&stor1);
  784.         return;
  785.     }
  786.     outop("cmp", 0, s2, s1);
  787.     return;
  788.  
  789.  
  790. #ifdef NOTDEF
  791.     if (s2->st_IntConst < -128 || s2->st_IntConst > 127 || s2->st_Size < 4) {
  792.         if (s1->st_Flags & SF_LEA) {
  793.         LockStorage(s2);
  794.         AllocAddrRegister(&stor1);
  795.         asm_move(exp, s1, &stor1);
  796.         UnlockStorage(s2);
  797.         outop("cmp", 0, &stor1, s2);
  798.         FreeRegister(&stor1);               xXX
  799.         *pcond = ReverseOrder(*pcond);        XXX
  800.         return;
  801.         }
  802.         outop("cmp", 0, s2, s1);
  803.         return;
  804.     }
  805. #endif
  806.     }
  807.  
  808.     if (s2->st_Flags & SF_LEA) {    /*  cmp ea,An    */
  809.     SWAPS(s1, s2);
  810.     *pcond = ReverseOrder(*pcond);
  811.     }
  812.  
  813.     if ((s1->st_Flags | s2->st_Flags) & SF_LEA) {
  814.     if (s1->st_Flags & SF_LEA) {
  815.         LockStorage(s2);
  816.         AllocAddrRegister(&stor1);
  817.         asm_move(exp, s1, &stor1);
  818.         UnlockStorage(s2);
  819.     } else {
  820.         stor1 = *s1;
  821.     }
  822.     if (s2->st_Flags & SF_LEA) {
  823.         LockStorage(s1);
  824.         AllocAddrRegister(&stor2);
  825.         asm_move(exp, s2, &stor2);
  826.         UnlockStorage(s1);
  827.     } else {
  828.         stor2 = *s2;
  829.     }
  830.     outop("cmp", 0, &stor2, &stor1);
  831.     if (s1->st_Flags & SF_LEA)
  832.         FreeRegister(&stor1);
  833.     if (s2->st_Flags & SF_LEA)
  834.         FreeRegister(&stor2);
  835.     return;
  836.     }
  837.     if (s1->st_Type == ST_Reg) {
  838.     outop("cmp", 0, s2, s1);
  839.     return;
  840.     }
  841.     if (s1->st_Size > 4) {
  842.     asm_blockop(exp, "cmp", *pcond, s1, s2);
  843.     } else {
  844.     LockStorage(s2);
  845.     AllocDataRegister(&stor1, s2->st_Size);
  846.     asm_move(exp, s1, &stor1);
  847.     UnlockStorage(s2);
  848.     outop("cmp", 0, s2, &stor1);
  849.     FreeRegister(&stor1);
  850.     }
  851. }
  852.  
  853. /*
  854.  *  asm_div()    d = s1 / s2    divs s2,s1  divs ea,Dn
  855.  *        d = s1 % s2
  856.  *
  857.  *  returns (1) TRUE if we had to make a call
  858.  */
  859.  
  860. long
  861. asm_div(Exp *exp, Stor *s1, Stor *s2, Stor *d, short mod)
  862. {
  863.     Stor ts1;
  864.     Stor ts2;
  865.     short ts1Flag = 0;
  866.     short ts2Flag = 0;
  867.     int opsize = 2;
  868.     char *dop;
  869.  
  870.     if ((s1->st_Flags | s2->st_Flags) & SF_UNSIGNED)
  871.     dop = (mod) ? "modu" : "divu";
  872.     else
  873.     dop = (mod) ? "mods" : "divs";
  874.  
  875.     /*
  876.      *
  877.      *    procedure call required?  means:    (1) if d long and s1 or s2 long
  878.      *                        (2) d not long and s2 long
  879.      */
  880.  
  881.     /*printf("; s1,s2,d %d %d %d\n", s1->st_Size, s2->st_Size, d->st_Size);*/
  882.  
  883.     if (s2->st_Size == 4 || (d->st_Size == 4 && s1->st_Size == 4)) {
  884.     if (MC68020Opt && !mod) {
  885.         opsize = 4;
  886.     } else {
  887.         CallAsmSupport(exp, dop, s1, s2, d, 1);
  888.         return(1);
  889.     }
  890.     }
  891.  
  892.     ts1 = *s1;
  893.     ts2 = *s2;
  894.  
  895.     /*
  896.      *    s1 directly addressable?  means:    (1) long
  897.      *                        (2) in data reg
  898.      *                        (3) s1 == d
  899.      *
  900.      *    (also implies d)
  901.      *
  902.      *    optimization:    if d is a register attempt to divide directly to it
  903.      */
  904.  
  905.     if ((s1->st_Type != ST_Reg || s1->st_RegNo >= RB_ADDR) || s1->st_Size != 4 || SameStorage(s1, d) == 0) {
  906.     if (d->st_Type == ST_Reg && d->st_RegNo < RB_ADDR && !SameRegister(s2, d)) {
  907.         ts1 = *d;
  908.         ts1.st_Size = 4;
  909.         ts1.st_Flags = s1->st_Flags;
  910.         asm_ext(exp, s1, &ts1, s1->st_Flags);
  911.     } else {
  912.         LockStorage(s2);
  913.         AllocDataRegister(&ts1, 4);
  914.         asm_ext(exp, s1, &ts1, s1->st_Flags);
  915.         UnlockStorage(s2);
  916.         ts1Flag = 1;
  917.     }
  918.     }
  919.  
  920.     /*
  921.      *    s2 addressable?     means:  (1) word sized
  922.      *                    (2) not in addr reg
  923.      */
  924.  
  925.     if (s2->st_Size != opsize || (s2->st_Type == ST_Reg && s2->st_RegNo >= RB_ADDR)) {
  926.     LockStorage(s1);
  927.     AllocDataRegister(&ts2, opsize);
  928.     asm_ext(exp, s2, &ts2, s2->st_Flags);
  929.     UnlockStorage(s1);
  930.     ts2Flag = 1;
  931.     }
  932.  
  933.     /*
  934.      *    output instruction
  935.      */
  936.  
  937.     dop = ((s1->st_Flags | s2->st_Flags) & SF_UNSIGNED) ? "divu" : "divs";
  938.  
  939.     outop(dop, opsize, &ts2, &ts1);
  940.  
  941.     if (mod) {
  942.     char c = ts1.st_RegNo + '0';
  943.     if (d->st_Size == 4 && (d->st_Flags & SF_UNSIGNED))
  944.         printf("\tclr.w\tD%c\n", c);
  945.     printf("\tswap\tD%c\n", c);
  946.     if (d->st_Size == 4 && !(d->st_Flags & SF_UNSIGNED))
  947.         printf("\text.l\tD%c\n", c);
  948.     } else {
  949.     char c = ts1.st_RegNo + '0';
  950.     if (d->st_Size == 4 && opsize != 4) {
  951.         if (d->st_Flags & SF_UNSIGNED)
  952.         printf("\tand.l\t#$FFFF,D%c\n", c);
  953.         else
  954.         printf("\text.l\tD%c\n", c);
  955.     }
  956.     }
  957.  
  958.     /*
  959.      *    Handle temporaries
  960.      */
  961.  
  962.     if (ts2Flag)
  963.     FreeRegister(&ts2);
  964.     if (ts1Flag) {
  965.     FreeRegister(&ts1);
  966.     ts1.st_Size = d->st_Size;
  967.     asm_move(exp, &ts1, d);
  968.     }
  969.     return(0);        /*    no call required */
  970. }
  971.  
  972. #ifdef NOTDEF
  973.  
  974. asm_div(exp, s1, s2, d, mod)
  975. Exp *exp;
  976. Stor *s1, *s2;
  977. Stor *d;
  978. short mod;
  979. {
  980.     short s2Size;
  981.     short sv;
  982.     int r;
  983.     char *dop;
  984.     char *dopc;
  985.  
  986.     if (s1->st_Flags & SF_LEA) {
  987.     Stor t;
  988.     LockStorage(s2);
  989.     AllocAddrRegister(&t);
  990.     asm_move(exp, s1, &t);
  991.     UnlockStorage(s2);
  992.     r = asm_div(&t, s2, d, mod);
  993.     FreeRegister(&t);
  994.     return(r);
  995.     }
  996.     if (s2->st_Flags & SF_LEA) {
  997.     Stor t;
  998.     LockStorage(s1);
  999.     AllocAddrRegister(&t);
  1000.     asm_move(exp, s2, &t);
  1001.     UnlockStorage(s1);
  1002.     r = asm_div(s1, &t, d, mod);
  1003.     FreeRegister(&t);
  1004.     return(r);
  1005.     }
  1006.  
  1007.     if (s2->st_Type == ST_IntConst) {
  1008.     if (s2->st_IntConst == 1) {
  1009.         if (mod)
  1010.         asm_movei(exp, 0, d);
  1011.         else
  1012.         asm_move(exp, s1, d);
  1013.         return(0);
  1014.     }
  1015.     if (s2->st_IntConst == -1) {
  1016.         if (mod)
  1017.         asm_movei(exp, 0, d);
  1018.         else
  1019.         asm_neg(exp, s1, d);
  1020.         return(0);
  1021.     }
  1022.     }
  1023.  
  1024.     /*
  1025.      *    note the last condition... if d = s1/s2 where s1's size is not
  1026.      *    a long (divs/divu always take a long for the numerator), we
  1027.      *    must make it a long whether or not it is already in a data reg.
  1028.      *    We cannot simply truncate the data reg since it might be a
  1029.      *    long register variable.
  1030.      */
  1031.  
  1032.     if (!SameStorage(s1, d) || d->st_Type != ST_Reg || d->st_RegNo >= RB_ADDR || s1->st_Size == 2) {
  1033.     Stor t;
  1034.     Stor u;
  1035.  
  1036.     LockStorage(s2);
  1037.     AllocDataRegister(&t, s1->st_Size);
  1038.     t.st_Flags |= s1->st_Flags & SF_UNSIGNED;
  1039.     u = t;
  1040.     u.st_Size = d->st_Size;
  1041.  
  1042.     if (s1->st_Type == ST_IntConst) {
  1043.         t.st_Size = 4;
  1044.         asm_move(exp, s1, &t);
  1045.     } else {
  1046.         if ((t.st_Flags & SF_UNSIGNED) && t.st_Size != 4)
  1047.         asm_movei(exp, 0, &t);
  1048.         asm_move(exp, s1, &t);
  1049.         if ((t.st_Flags & SF_UNSIGNED) == 0 && t.st_Size != 4) {
  1050.         if (t.st_Size == 1)
  1051.             outop("ext", 2, NULL, &t);
  1052.         if (t.st_Size == 2)
  1053.             outop("ext", 4, NULL, &t);
  1054.         }
  1055.         t.st_Size = 4;
  1056.     }
  1057.     UnlockStorage(s2);
  1058.     r = asm_div(&t, s2, &u, mod);
  1059.     asm_move(exp, &u, d);
  1060.     FreeRegister(&t);
  1061.     return(r);
  1062.     }
  1063.  
  1064.     s2Size = s2->st_Size;
  1065.     if (s2->st_Type == ST_IntConst)
  1066.     s2->st_Size = SizeFitSU(s2->st_IntConst, s2);
  1067.  
  1068.     /*
  1069.      *    s1 = s1 / s2, s1 is a DReg.  note that s1 and d might
  1070.      *    have different sizes.  s2 determines sign.
  1071.      *        s1  2,4
  1072.      *        s2  2,4 s/u
  1073.      *        d   2,4
  1074.      *
  1075.      */
  1076.  
  1077.     Assert(s1->st_Size != 1 && s2->st_Size != 1 && d->st_Size != 1);
  1078.  
  1079.     sv = (~s1->st_Size & 2) | (s2->st_Size & 4) | ((d->st_Size & 4) << 1);
  1080.     if (s2->st_Flags & SF_UNSIGNED)
  1081.     ++sv;
  1082.  
  1083.     /*
  1084.      *    odd == unsigned divide
  1085.      *    msb 8 for d size == 32, lsb 8 for d size == 16
  1086.      *    & 4 : s2 size 32
  1087.      *    & 2 : s1 size 32
  1088.      */
  1089.  
  1090.     dop = (sv & 1) ? "divu" : "divs";
  1091.     if (mod)
  1092.     dopc = (sv & 1) ? "modu" : "mods";
  1093.     else
  1094.     dopc = dop;
  1095.  
  1096.     if (sv >= 4) {    /*  >= 8 32 bit dest,    else 16 bit dest    */
  1097.     r = 1;
  1098.     CallAsmSupport(exp, dopc, s1, s2, d, 1);
  1099.     } else {        /*  32/16 or 32%16  */
  1100.     r = 0;
  1101.     outop(dop, 2, s2, d);
  1102.     if (mod) {
  1103.         char c = d->st_RegNo + '0';
  1104.         if (d->st_Size == 4 && (d->st_Flags & SF_UNSIGNED))
  1105.         printf("\tclr.w\tD%c\n", c);
  1106.         printf("\tswap\tD%c\n", c);
  1107.         if (d->st_Size == 4 && !(d->st_Flags & SF_UNSIGNED))
  1108.         printf("\text.l\tD%c\n", c);
  1109.     } else {
  1110.         char c = d->st_RegNo + '0';
  1111.         if (d->st_Size == 4) {
  1112.         if (d->st_Flags & SF_UNSIGNED)
  1113.             printf("\tand.l\t#$FFFF,D%c\n", c);
  1114.         else
  1115.             printf("\text.l\tD%c\n", c);
  1116.         }
  1117.     }
  1118.     }
  1119.     s2->st_Size = s2Size;
  1120. }
  1121.  
  1122. #endif
  1123.  
  1124. /*
  1125.  *  asm_mul()    d = s1 * s2    d = s1 * #const
  1126.  *
  1127.  *  Returns (1) TRUE if we had to make a call.    asm_mul_requires_call()
  1128.  *  deals with simplistic cases, erroring on the side of returning TRUE
  1129.  *  sometimes even if no call will be made, but never returning FALSE
  1130.  *  and then making a call.
  1131.  */
  1132.  
  1133. long
  1134. asm_mul_requires_call(offset)
  1135. long offset;
  1136. {
  1137.     if (offset >= -1 && offset <= 1)
  1138.     return(0);
  1139.     if (offset < 0)
  1140.     return(1);
  1141.     if (PowerOfTwo(offset) >= 0)
  1142.     return(0);
  1143.     return(1);
  1144. }
  1145.  
  1146. /*
  1147.  *  d = s1 * s2     muls ea,Dn        muls s2,s1
  1148.  *
  1149.  *  returns (1) TRUE if we had to make a call
  1150.  */
  1151.  
  1152. long
  1153. asm_mul(exp, s1, s2, d)
  1154. Exp *exp;
  1155. Stor *s1, *s2;
  1156. Stor *d;
  1157. {
  1158.     Stor ts1;
  1159.     Stor ts2;
  1160.     short ts1Flag = 0;
  1161.     short ts2Flag = 0;
  1162.     int opsize = 2;
  1163.     char *mop = ((s1->st_Flags | s2->st_Flags) & SF_UNSIGNED) ? "mulu" : "muls";
  1164.  
  1165.     /*
  1166.      *    optimize constant placement, want constant in s2
  1167.      *    optimize destination, want destination == s1
  1168.      */
  1169.  
  1170.     if (s1->st_Type == ST_IntConst)
  1171.     SWAPS(s1,s2);
  1172.     if (SameStorage(s2,d))
  1173.     SWAPS(s1,s2);
  1174.  
  1175.     /*
  1176.      *    optimize for constant multiply
  1177.      */
  1178.  
  1179.     ts1 = *s1;
  1180.     ts2 = *s2;
  1181.  
  1182.     if (s2->st_Type == ST_IntConst) {
  1183.     long n;
  1184.  
  1185.     switch (s2->st_IntConst) {
  1186.     case -1:
  1187.         if (s1->st_Size != d->st_Size) {
  1188.         if (d->st_Type == ST_Reg && d->st_Type < RB_ADDR) {
  1189.             asm_ext(exp, s1, d, s1->st_Flags);
  1190.             asm_neg(exp, d, d);
  1191.         } else {
  1192.             AllocDataRegister(&ts1, d->st_Size);
  1193.             asm_ext(exp, s1, &ts1, s1->st_Flags);
  1194.             asm_neg(exp, &ts1, d);
  1195.             FreeRegister(&ts1);
  1196.         }
  1197.         } else {
  1198.         asm_neg(exp, s1, d);
  1199.         }
  1200.         return(0);
  1201.     case 0:
  1202.         asm_movei(exp, 0, d);
  1203.         return(0);
  1204.     case 1:
  1205.         asm_ext(exp, s1, d, s1->st_Flags);
  1206.         return(0);
  1207.     }
  1208.  
  1209.     n = PowerOfTwo(s2->st_IntConst);
  1210.     if (n >= 0) {
  1211.         AllocConstStor(&ts1, n, &LongType);
  1212.         asm_shift(exp, -1, s1, &ts1, d);
  1213.         return(0);
  1214.     }
  1215.     ts2.st_Size = SizeFitSU(s2->st_IntConst, s2);
  1216.     }
  1217.  
  1218.     /*
  1219.      *    procedure call required?  means:    (1) either source is long
  1220.      */
  1221.  
  1222.     if (ts1.st_Size == 4 || ts2.st_Size == 4) {
  1223.     if (MC68020Opt) {
  1224.         opsize = 4;
  1225.     } else {
  1226.         CallAsmSupport(exp, mop, &ts1, &ts2, d, -1);
  1227.         return(1);
  1228.     }
  1229.     }
  1230.  
  1231.     /*
  1232.      *    s1 directly addressable? means:  (1) word
  1233.      *                     (2) in data reg
  1234.      *                     (3) s1 == d
  1235.      *    (also implies d)
  1236.      *
  1237.      *    optimization:    if d is a register attempt to multiply directly
  1238.      *            to it
  1239.      */
  1240.  
  1241.     if ((s1->st_Type != ST_Reg || s1->st_RegNo >= RB_ADDR) || s1->st_Size != opsize || SameStorage(s1, d) == 0) {
  1242.     if (d->st_Type == ST_Reg && d->st_RegNo < RB_ADDR && !SameRegister(s2, d)) {
  1243.         ts1 = *d;
  1244.         ts1.st_Size = opsize;
  1245.         ts1.st_Flags = s1->st_Flags;
  1246.         asm_ext(exp, s1, &ts1, s1->st_Flags);
  1247.     } else {
  1248.         LockStorage(s2);
  1249.         AllocDataRegister(&ts1, opsize);
  1250.         asm_ext(exp, s1, &ts1, s1->st_Flags);
  1251.         UnlockStorage(s2);
  1252.         ts1Flag = 1;
  1253.     }
  1254.     }
  1255.  
  1256.     /*
  1257.      *    s2 addressable?     means:  (1) word
  1258.      *                    (2) not in address register
  1259.      */
  1260.  
  1261.     if (s2->st_Size != opsize || (s2->st_Type == ST_Reg && s2->st_RegNo >= RB_ADDR)) {
  1262.     LockStorage(s1);
  1263.     AllocDataRegister(&ts2, opsize);
  1264.     asm_ext(exp, s2, &ts2, s2->st_Flags);
  1265.     UnlockStorage(s1);
  1266.     ts2Flag = 1;
  1267.     }
  1268.  
  1269.     /*
  1270.      *    output instruction, result is a longword
  1271.      */
  1272.  
  1273.     outop(mop, opsize, &ts2, &ts1);
  1274.  
  1275.     /*
  1276.      *    Handle temporaries
  1277.      */
  1278.  
  1279.     if (ts2Flag)
  1280.     FreeRegister(&ts2);
  1281.     if (ts1Flag) {
  1282.     FreeRegister(&ts1);
  1283.     ts1.st_Size = d->st_Size;
  1284.     asm_move(exp, &ts1, d);
  1285.     }
  1286.     return(0);        /*    no call required */
  1287. }
  1288.  
  1289.  
  1290. #ifdef NOTDEF
  1291.  
  1292. asm_mul(exp, s1, s2, d)
  1293. Exp *exp;
  1294. Stor *s1, *s2;
  1295. Stor *d;
  1296. {
  1297.     short s2Size;
  1298.     short sv;
  1299.     int r = 0;
  1300.     char *mop;
  1301.  
  1302.     if (s1->st_Flags & SF_LEA) {
  1303.     Stor t;
  1304.     LockStorage(s2);
  1305.     AllocAddrRegister(&t);
  1306.     asm_move(exp, s1, &t);
  1307.     UnlockStorage(s2);
  1308.     r = asm_mul(&t, s2, d);
  1309.     FreeRegister(&t);
  1310.     return(r);
  1311.     }
  1312.     if (s2->st_Flags & SF_LEA) {
  1313.     Stor t;
  1314.     LockStorage(s1);
  1315.     AllocAddrRegister(&t);
  1316.     asm_move(exp, s2, &t);
  1317.     UnlockStorage(s1);
  1318.     r = asm_mul(s1, &t, d);
  1319.     FreeRegister(&t);
  1320.     return(r);
  1321.     }
  1322.  
  1323.     if (SameStorage(s2,d))
  1324.     SWAPS(s1,s2);
  1325.  
  1326.     if (s1->st_Type == ST_IntConst)
  1327.     SWAPS(s1,s2);
  1328.  
  1329.     s2Size = s2->st_Size;
  1330.     if (s2->st_Type == ST_IntConst) {
  1331.     int n;
  1332.     switch(s2->st_IntConst) {
  1333.     case -1:
  1334.         asm_neg(s1, d);
  1335.         return(0);
  1336.     case 0:
  1337.         asm_movei(exp, 0, d);
  1338.         return(0);
  1339.     case 1:
  1340.         asm_move(exp, s1, d);
  1341.         return(0);
  1342.     }
  1343.  
  1344.     n = PowerOfTwo(s2->st_IntConst);
  1345.     if (n >= 0) {
  1346.         Stor con;
  1347.         AllocConstStor(&con, n, &LongType);
  1348.         asm_shift(exp, -1, s1, &con, d);
  1349.         return(0);
  1350.     }
  1351.     s2->st_Size = SizeFitSU(s2->st_IntConst, s2);
  1352.     }
  1353.  
  1354.  
  1355.     if (!SameStorage(s1, d) || d->st_Type != ST_Reg || d->st_RegNo >= RB_ADDR) {
  1356.     Stor t;
  1357.     Stor u;
  1358.  
  1359.     LockStorage(s2);
  1360.     AllocDataRegister(&t, s1->st_Size);
  1361.     u = t;
  1362.     u.st_Size = d->st_Size;
  1363.  
  1364.     asm_move(exp, s1, &t);
  1365.     UnlockStorage(s2);
  1366.     r = asm_mul(&t, s2, &u);
  1367.     asm_move(exp, &u, d);
  1368.     FreeRegister(&t);
  1369.     s2->st_Size = s2Size;
  1370.     return(r);
  1371.     }
  1372.  
  1373.  
  1374.     /*
  1375.      *    s1 = s1 * s2, s1 is a DReg.  note that s1 and d might
  1376.      *    have different sizes.  s2 determines sign.
  1377.      *        s1  2,4
  1378.      *        s2  2,4 s/u
  1379.      *        d   2,4
  1380.      *
  1381.      */
  1382.  
  1383.     Assert(s1->st_Size != 1 && s2->st_Size != 1 && d->st_Size != 1);
  1384.  
  1385.     sv = (~s1->st_Size & 2) | (s2->st_Size & 4) | ((d->st_Size & 4) << 1);
  1386.     if (s2->st_Flags & SF_UNSIGNED)
  1387.     ++sv;
  1388.  
  1389.     /*
  1390.      *    odd == unsigned multiply
  1391.      *    msb 8 for d size == 32, lsb 8 for d size == 16
  1392.      *    & 4 : s2 size 32
  1393.      *    & 2 : s1 size 32
  1394.      */
  1395.  
  1396.     mop = (sv & 1) ? "mulu" : "muls";
  1397.  
  1398.     if (sv <= 9) {
  1399.     /*  s/u  ? * ? -> 16    */
  1400.     Stor t = *s2;
  1401.     if (t.st_Type != ST_Reg && (sv & 4))
  1402.         t.st_Offset += 2;
  1403.     outop(mop, 2, &t, d);
  1404.     r = 0;
  1405.     } else {
  1406.     /*  s 32 * 32 -> 32   */
  1407.     /*  u 32 * 32 -> 32   */
  1408.  
  1409.     CallAsmSupport(exp, mop, s1, s2, d, -1);
  1410.     r = 1;
  1411.     }
  1412.     s2->st_Size = s2Size;
  1413.     return(r);
  1414. }
  1415.  
  1416. #endif
  1417.  
  1418. void
  1419. asm_shift(exp, dir, s1, s2, d)
  1420. Exp *exp;
  1421. long dir;
  1422. Stor *s1;
  1423. Stor *s2;
  1424. Stor *d;
  1425. {
  1426.     char *str = "asl";
  1427.     static short Recur = 3;
  1428.  
  1429.     if (--Recur == 0)
  1430.     {
  1431.     dbprintf(("asm_shift recur"));
  1432.     Assert(0);
  1433.     }
  1434.  
  1435.     if (dir > 0) {
  1436.     if (s1->st_Flags & SF_UNSIGNED)
  1437.         str = "lsr";
  1438.     else
  1439.         str = "asr";
  1440.     }
  1441.  
  1442.     /*
  1443.      *    XXX optimize 1 << ?
  1444.      */
  1445.  
  1446.  
  1447.     if (!SameStorage(s1, d) || SameStorage(s2, d) || s1->st_Size != d->st_Size || (s1->st_Type == ST_Reg && s1->st_RegNo >= RB_ADDR)) {
  1448.     Stor nd;
  1449.  
  1450. wc:
  1451.     LockStorage(s2);
  1452.     AllocDataRegister(&nd, Max(s1->st_Size, d->st_Size));
  1453.     nd.st_Flags |= s1->st_Flags & SF_UNSIGNED;
  1454.     asm_move_cast(exp, s1, &nd);
  1455.     UnlockStorage(s2);
  1456.     asm_shift(exp, dir, &nd, s2, &nd);
  1457.     asm_move_cast(exp, &nd, d);
  1458.     FreeRegister(&nd);
  1459.     ++Recur;
  1460.     return;
  1461.     }
  1462.     /*
  1463.      *    s1 == d
  1464.      */
  1465.     if (s1->st_Type != ST_Reg) {
  1466.     if (s2->st_Type == ST_IntConst && s2->st_IntConst == 1 && d->st_Size == 2) {
  1467.         outop(str, 0, NULL, d);
  1468.         ++Recur;
  1469.         return;
  1470.     }
  1471.     /*puts("SNR");*/
  1472.     goto wc;
  1473.     }
  1474.  
  1475.     /*
  1476.      *    s1 == d == register, s2 integer in range?
  1477.      */
  1478.     if (s2->st_Type == ST_IntConst && s2->st_IntConst > 0 && s2->st_IntConst <= 8) {
  1479.     outop(str, 0, s2, d);
  1480.     ++Recur;
  1481.     return;
  1482.     }
  1483.  
  1484.     /*
  1485.      *    s2 out of range, stick in register too
  1486.      */
  1487.  
  1488.     if (s2->st_Type == ST_Reg && s2->st_RegNo < RB_ADDR) {
  1489.     outop(str, 0, s2, d);
  1490.     } else {
  1491.     Stor cnt;
  1492.  
  1493.     AllocDataRegister(&cnt, s2->st_Size);
  1494.     asm_move(exp, s2, &cnt);
  1495.     outop(str, 0, &cnt, d);
  1496.     FreeRegister(&cnt);
  1497.     }
  1498.     ++Recur;
  1499. }
  1500.  
  1501. /*
  1502.  *  Compiler Support call (passing simple data <= 4 bytes)
  1503.  *
  1504.  *    order=1     order=0    order=-1
  1505.  *  s1        D0          D1    either way
  1506.  *  s2        D1          D0
  1507.  *
  1508.  *  (call)
  1509.  *  D0->d
  1510.  *
  1511.  *  handle byte/word cases (ext into long)
  1512.  */
  1513.  
  1514. void
  1515. CallAsmSupport(Exp *exp,char *mop, Stor *s1, Stor *s2, Stor *d, short orderReq)
  1516. {
  1517.     Stor rd0, rd1;
  1518.     Stor ss1;
  1519.     Stor ss2;
  1520.     ulong mask = 0;
  1521.  
  1522.     GenFlagCallMade();
  1523.  
  1524.     if (d)
  1525.     {
  1526.     if (d->st_Type == ST_Reg) {
  1527.         mask = 1 << d->st_RegNo;
  1528.     } else if (d->st_Type == ST_RegIndex) {
  1529.         if (((1 << d->st_RegNo) | (1 << d->st_RegNo2)) & REGSCRATCH)
  1530.         {
  1531.         dbprintf(("scratch overrun %08lx\n", mask));
  1532.         Assert(0);
  1533.         }
  1534.     }
  1535.     }
  1536.  
  1537.     if ((mask = ~mask & GetLockedScratch()) != 0) {
  1538.     asm_save_regs(mask);
  1539.     printf("; Saved locked: %08lx\n", mask);
  1540.     }
  1541.  
  1542.     AllocDataRegisterAbs(&rd0, 4, RB_D0);
  1543.     AllocDataRegisterAbs(&rd1, 4, RB_D1);
  1544.  
  1545.     AddAuxSub(mop);
  1546.  
  1547.     if (s1 && s1->st_Type == ST_FltConst) {
  1548.     long fpv;
  1549.  
  1550.     Assert(s1->st_Size == 4);
  1551.     asm_fltconst(exp, s1, &fpv);
  1552.     AllocConstStor(&ss1, fpv, &LongType);
  1553.     s1 = &ss1;
  1554.     }
  1555.     if (s2 && s2->st_Type == ST_FltConst) {
  1556.     long fpv;
  1557.  
  1558.     Assert(s2->st_Size == 4);
  1559.     asm_fltconst(exp, s2, &fpv);
  1560.     AllocConstStor(&ss2, fpv, &LongType);
  1561.     s2 = &ss2;
  1562.     }
  1563.  
  1564.     if (s1 && s2) {
  1565.     if (SameRegister(s2, &rd0)) {        /*    s2 uses D0! */
  1566.         if (SameRegister(s1, &rd1)) {   /*    s1 uses D1! */
  1567.         /*
  1568.          *  put in reversed registers
  1569.          */
  1570.  
  1571.         asm_ext(exp, s1, &rd1, s1->st_Flags);
  1572.         asm_ext(exp, s2, &rd0, s2->st_Flags);
  1573.         if (orderReq > 0)
  1574.             printf("\texg\tD0,D1\n");
  1575.         } else {
  1576.         if (orderReq > 0) {
  1577.             asm_ext(exp, s2, &rd1, s2->st_Flags);
  1578.             asm_ext(exp, s1, &rd0, s1->st_Flags);
  1579.         } else {
  1580.             asm_ext(exp, s2, &rd0, s2->st_Flags);
  1581.             asm_ext(exp, s1, &rd1, s1->st_Flags);
  1582.         }
  1583.         }
  1584.     } else {
  1585.         asm_ext(exp, s1, &rd0, s1->st_Flags);
  1586.         asm_ext(exp, s2, &rd1, s2->st_Flags);
  1587.         if (orderReq == 0)
  1588.         printf("\texg\tD0,D1\n");
  1589.     }
  1590.     } else if (s1) {
  1591.     asm_ext(exp, s1, &rd0, s1->st_Flags);
  1592.     } else if (s2) {
  1593.     asm_ext(exp, s2, &rd1, s2->st_Flags);
  1594.     }
  1595.  
  1596.     if (SmallCode)
  1597.     printf("\tjsr\t__%s(pc)\n", mop);
  1598.     else
  1599.     printf("\tjsr\t__%s\n", mop);
  1600.  
  1601.     if (d) {
  1602.     if (d->st_Type != ST_Reg || d->st_RegNo != RB_D0) {
  1603.         rd0.st_Size = d->st_Size;
  1604.         asm_move(exp, &rd0, d);
  1605.         /*printf("\tmove.l\tD0,%s\n", StorToString(d, NULL));*/
  1606.     }
  1607.     }
  1608.  
  1609.     FreeRegister(&rd0);
  1610.     FreeRegister(&rd1);
  1611.  
  1612.     asm_restore_regs(mask);
  1613. }
  1614.  
  1615. /*
  1616.  *  BITFIELDS
  1617.  */
  1618.  
  1619. #ifdef REGISTERED
  1620.  
  1621. void
  1622. asm_bfext(exp, s, d)
  1623. Exp *exp;
  1624. Stor *s;
  1625. Stor *d;
  1626. {
  1627.     Type *t;
  1628.     Stor dtmp;
  1629.     Stor stmp;
  1630.     short tmpFlag;
  1631.  
  1632.     OptimizeBitField(s, &stmp);
  1633.  
  1634.  
  1635.     LockStorage(&stmp);
  1636.     if (d->st_Type==ST_Reg && d->st_RegNo<RB_ADDR && !SameRegister(&stmp, d)){
  1637.     dtmp = *d;
  1638.     tmpFlag = 0;
  1639.     } else {
  1640.     AllocDataRegister(&dtmp, d->st_Size);
  1641.     tmpFlag = 1;
  1642.     }
  1643.     UnlockStorage(&stmp);
  1644.  
  1645.     Assert(stmp.st_Size > 1);
  1646.  
  1647.     if (stmp.st_Flags & SF_UNSIGNED) {
  1648.     switch(stmp.st_Size) {
  1649.     case 2:
  1650.         t = &UShortType;
  1651.         break;
  1652.     default:
  1653.         t = &ULongType;
  1654.         break;
  1655.     }
  1656.     } else {
  1657.     switch(stmp.st_Size) {
  1658.     case 2:
  1659.         t = &ShortType;
  1660.         break;
  1661.     default:
  1662.         t = &LongType;
  1663.         break;
  1664.     }
  1665.     }
  1666.  
  1667.     dbprintf(("BitFieldExt %s[siz=%ld] ->", StorToString(&stmp, NULL), stmp.st_Size));
  1668.     dbprintf(("%s (off=%d, siz=%d)\n", StorToString(&dtmp, NULL), stmp.st_BOffset, stmp.st_BSize));
  1669.     Assert(stmp.st_Flags & SF_BITFIELD);
  1670.  
  1671.     /*
  1672.      *    extract a bit field.  A 1 bit bitfield is extracted via a btst/scc/neg
  1673.      */
  1674.  
  1675.     if (stmp.st_BSize == 1) {
  1676.     Stor st;
  1677.  
  1678.     AllocConstStor(&st, 1 << stmp.st_BOffset, t);
  1679.     st.st_Size = stmp.st_Size;
  1680.     if (stmp.st_Flags & SF_UNSIGNED) {
  1681.         if (dtmp.st_Size != 1)
  1682.         asm_movei(exp, 0, &dtmp);
  1683.         asm_test_and(exp, &stmp, &st);
  1684.         asm_sccb(exp, &dtmp, COND_NEQ, 0);
  1685.     } else {
  1686.         asm_test_and(exp, &stmp, &st);
  1687.         asm_sccb(exp, &dtmp, COND_NEQ, 1);
  1688.         if (dtmp.st_Size != 1) {
  1689.         st = dtmp;
  1690.         st.st_Size = 1;
  1691.         asm_ext(exp, &st, &dtmp, 0);
  1692.         }
  1693.     }
  1694.     } else {
  1695.     Stor st;
  1696.     short d_size = dtmp.st_Size;
  1697.     long mask;
  1698.  
  1699.     /*
  1700.      *  unsigned breakout optimization
  1701.      */
  1702.  
  1703.     dtmp.st_Size = stmp.st_Size;
  1704.     mask = ((ulong)-1 >> (32 - stmp.st_BSize)) << stmp.st_BOffset;
  1705.  
  1706.     /* if (stmp.st_Flags & SF_UNSIGNED) { */
  1707.         if (dtmp.st_Size != 4)
  1708.         asm_movei(exp, 0, &dtmp);
  1709.     /* } */
  1710.     AllocConstStor(&st, mask, t);            /*    mask source -> d */
  1711.     asm_and(exp, &stmp, &st, &dtmp);
  1712.  
  1713.     if (stmp.st_BOffset) {                /*    shift it    */
  1714.         long flags = dtmp.st_Flags;
  1715.  
  1716.         dtmp.st_Flags |= SF_UNSIGNED;
  1717.         AllocConstStor(&st, stmp.st_BOffset, t);
  1718.         asm_shift(exp, 1, &dtmp, &st, &dtmp);
  1719.         dtmp.st_Flags = flags;
  1720.     }
  1721.  
  1722.     /*
  1723.      *  if signed then sign-extend, else if unsigned done (0 fill
  1724.      *  above handles word case).  When signed, we must ensure that
  1725.      *  the entire result type is set negative, so we restore the
  1726.      *  destination size immediately.
  1727.      */
  1728.  
  1729.     if ((stmp.st_Flags & SF_UNSIGNED) == 0) {
  1730.         long l1 = AllocLabel();
  1731.  
  1732.         AllocConstStor(&st, 1 << (stmp.st_BSize - 1), t);
  1733.         asm_test_and(exp, &st, &dtmp);
  1734.         asm_condbra(COND_EQ, l1);    /*  skip if not negative */
  1735.                     /*  if negative, make so */
  1736.         AllocConstStor(&st, -1 << stmp.st_BSize, t);
  1737.         dtmp.st_Size = d_size;
  1738.         st.st_Size = d_size;
  1739.         asm_or(exp, &st, &dtmp, &dtmp);
  1740.         asm_label(l1);
  1741.     } else {
  1742.         dtmp.st_Size = d_size;
  1743.     }
  1744.     }
  1745.     if (tmpFlag) {
  1746.     asm_move(exp, &dtmp, d);
  1747.     FreeRegister(&dtmp);
  1748.     }
  1749. }
  1750.  
  1751. void
  1752. asm_bfsto(exp, s, d)
  1753. Exp *exp;
  1754. Stor *s;
  1755. Stor *d;
  1756. {
  1757.     long mask;
  1758.     Type *t;
  1759.     Stor dtmp;
  1760.  
  1761.     OptimizeBitField(d, &dtmp);
  1762.  
  1763.     mask = ((ulong)-1 >> (32 - dtmp.st_BSize)) << dtmp.st_BOffset;
  1764.     t = (dtmp.st_Size == 2) ? &UShortType : &ULongType;
  1765.  
  1766.  
  1767.     dbprintf(("BitFieldSto %s ->", StorToString(s, NULL)));
  1768.     dbprintf(("%s (off=%d, siz=%d)\n", StorToString(&dtmp, NULL), dtmp.st_BOffset, dtmp.st_BSize));
  1769.     Assert(dtmp.st_Flags & SF_BITFIELD);
  1770.  
  1771.     /*
  1772.      *    store into a bit field.
  1773.      */
  1774.  
  1775.     if (s->st_Type == ST_IntConst) {
  1776.     long valu;
  1777.     Stor st;
  1778.  
  1779.     valu = mask & (s->st_IntConst << dtmp.st_BOffset);
  1780.  
  1781.     dbprintf(("valu %08lx\nmask %08lx\n", valu, mask));
  1782.  
  1783.     if (valu == 0) {
  1784.         AllocConstStor(&st, ~mask, t);
  1785.         asm_and(exp, &st, &dtmp, &dtmp);
  1786.     } else if (valu == mask) {
  1787.         AllocConstStor(&st, mask, t);
  1788.         asm_or(exp, &st, &dtmp, &dtmp);
  1789.     } else {
  1790.         AllocConstStor(&st, ~mask, t);
  1791.         asm_and(exp, &st, &dtmp, &dtmp);
  1792.         AllocConstStor(&st, valu, t);
  1793.         asm_or(exp, &st, &dtmp, &dtmp);
  1794.     }
  1795.     } else {
  1796.     Stor st;
  1797.     Stor tm;
  1798.  
  1799.     if (dtmp.st_BSize == 1) {     /*  test bit 0, bset/bclr   */
  1800.         long l1 = AllocLabel();
  1801.         long l2 = AllocLabel();
  1802.  
  1803.         AllocConstStor(&st, 1, t);
  1804.         st.st_Size = s->st_Size;
  1805.         asm_test_and(exp, &st, s);
  1806.         asm_condbra(COND_EQ, l1);
  1807.         AllocConstStor(&st, mask, t);
  1808.         asm_or(exp, &st, &dtmp, &dtmp);
  1809.         asm_branch(l2);
  1810.         asm_label(l1);
  1811.         AllocConstStor(&st, ~mask, t);
  1812.         asm_and(exp, &st, &dtmp, &dtmp);
  1813.         asm_label(l2);
  1814.     } else {
  1815.         Stor t2;
  1816.         AllocDataRegister(&tm, dtmp.st_Size);
  1817.         AllocDataRegister(&t2, dtmp.st_Size);
  1818.  
  1819.         if (s->st_Size < tm.st_Size) {
  1820.         asm_ext(exp, s, &tm, s->st_Flags);   /*  ext & mask     */
  1821.         } else {
  1822.         tm.st_Size = s->st_Size;
  1823.         asm_move(exp, s, &tm);
  1824.         tm.st_Size = dtmp.st_Size;
  1825.         }
  1826.  
  1827.         AllocConstStor(&st, mask >> dtmp.st_BOffset, t);
  1828.         asm_and(exp, &st, &tm, &tm);
  1829.  
  1830.         if (dtmp.st_BOffset) {              /*  shift it          */
  1831.         AllocConstStor(&st, dtmp.st_BOffset, t);
  1832.         asm_shift(exp, 0, &tm, &st, &tm);
  1833.         }
  1834.         AllocConstStor(&st, ~mask, t);
  1835.         asm_and(exp, &st, &dtmp, &t2);           /*  mask destination    */
  1836.         asm_or(exp, &tm, &t2, &dtmp);           /*  or in changes       */
  1837.  
  1838.         FreeRegister(&t2);
  1839.         FreeRegister(&tm);
  1840.     }
  1841.     }
  1842. }
  1843.  
  1844. void
  1845. asm_bftst(exp, s)
  1846. Exp *exp;
  1847. Stor *s;
  1848. {
  1849.     Stor st;
  1850.     Stor stmp;
  1851.     long mask;
  1852.     Type *t;
  1853.  
  1854.     OptimizeBitField(s, &stmp);
  1855.     t = (stmp.st_Size == 2) ? &UShortType : &ULongType;
  1856.  
  1857.     dbprintf(("BitFieldTst %s (off=%d, siz=%d)\n", StorToString(&stmp, NULL), stmp.st_BOffset, stmp.st_BSize));
  1858.  
  1859.     /*
  1860.      *    test a bit field.  A 1 bit bitfield is tested with btst
  1861.      */
  1862.  
  1863.     mask = ((ulong)-1 >> (32 - stmp.st_BSize)) << stmp.st_BOffset;
  1864.     AllocConstStor(&st, mask, t);
  1865.     asm_test_and(exp, &stmp, &st);
  1866. }
  1867.  
  1868. void
  1869. OptimizeBitField(s, d)
  1870. Stor *s;
  1871. Stor *d;
  1872. {
  1873.     *d = *s;
  1874.  
  1875.     if (d->st_Size == 4) {
  1876.     if (d->st_BOffset < 16 && d->st_BOffset + d->st_BSize < 16) {
  1877.         d->st_Size = 2;
  1878.         d->st_Offset += 2;
  1879.     } else if (d->st_BOffset > 16) {
  1880.         d->st_BOffset -= 16;
  1881.         d->st_Size = 2;
  1882.     }
  1883.     }
  1884. }
  1885.  
  1886. #else
  1887.  
  1888. void
  1889. asm_bfext(exp, s, d)
  1890. Exp *exp;
  1891. Stor *s;
  1892. Stor *d;
  1893. {
  1894.     cerror(EUNREG, "bitfields");
  1895. }
  1896.  
  1897. void
  1898. asm_bfsto(exp, s, d)
  1899. Exp *exp;
  1900. Stor *s;
  1901. Stor *d;
  1902. {
  1903.     cerror(EUNREG, "bitfields");
  1904. }
  1905.  
  1906. void
  1907. asm_bftst(exp, s)
  1908. Exp *exp;
  1909. Stor *s;
  1910. {
  1911.     cerror(EUNREG, "bitfields");
  1912. }
  1913.  
  1914. #endif
  1915.  
  1916. void
  1917. asm_illegal(void)
  1918. {
  1919.     puts("\tdc.w\t$4AFC");
  1920. }
  1921.